home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / alloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-11  |  9.7 KB  |  382 lines

  1. /* @(#)src/alloc.c    1.4 7/11/92 11:47:12 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * alloc.c:
  13.  *    storage allocation with panics on errors
  14.  *        The functions in this file may be replaced in the future when
  15.  *        daemon mode is implemented, to make it easier to reclaim
  16.  *        storage.
  17.  *
  18.  *    block storage allocation
  19.  *        This allows a given stroage allocation to be associated 
  20.  *        with a group of other storage allocations.  It is
  21.  *        possible to free or test for existence of the class.
  22.  *
  23.  *        A block a pointer to a chain of segments.  Each segment
  24.  *        refers to one storage allocation.  A block also contains
  25.  *        the total number of bytes allocated.  If this number is
  26.  *        zero, then no stroage is associated with the block.
  27.  *
  28.  *    external functions: xmalloc, xrealloc, xfree, 
  29.  *                balloc, brealloc, bfree,
  30.  *                alloc_block, re_block, free_block
  31.  */
  32.  
  33. #include <stdio.h>
  34. #include "defs.h"
  35. #include "smail.h"
  36. #include "exitcodes.h"
  37. #include "log.h"
  38. #include "alloc.h"
  39. #ifndef DEPEND
  40. # include "extern.h"
  41. #endif
  42.  
  43. /* the master block of blocks */
  44. static struct block master = {(struct bseg *)0, 0};
  45.  
  46. /* the block for pmalloc(), prealloc() and pfree() macros */
  47. static struct block perm_block = {(struct bseg *)0, 0};
  48. struct block *perm = &perm_block;
  49.  
  50. /* default block for 0 based life time */
  51. static struct block default_block = {(struct bseg *)0, 0};
  52. static struct block *def_block = &default_block;
  53.  
  54. /* variable exported for the X_CHECK macro */
  55. int x_dont_panic = TRUE;              /* if TRUE, X_CHECK won't call panic */
  56.  
  57. extern char *malloc();
  58. extern char *realloc();
  59. extern void free();
  60.  
  61.  
  62. /*
  63.  * xmalloc, xrealloc, xfree - per message malloc and realloc and free
  64.  *                  with aborts on error
  65.  *
  66.  * The following two routines are an interface to xmalloc and xrealloc
  67.  * which frees other functions from having to worry about whether
  68.  * a memory full error occurs.  There is seldom anything graceful
  69.  * to do when this happens, and it happens seldom on machines with
  70.  * a reasonable VM space.  So just panic about the problem and don't
  71.  * bother returning.
  72.  *
  73.  * In the future, the x-style allocation routines will be used for
  74.  * allocation of spaces which will be reclaimed after processing one
  75.  * message.
  76.  */
  77. char *
  78. xmalloc(size)
  79.     unsigned size;            /* size of region to allocate */
  80. {
  81.     register char *ret;            /* region returned by malloc */
  82.  
  83.     ret = malloc(size + sizeof(int));
  84.     if (!ret) {
  85.     panic(EX_SOFTWARE, "malloc(%d) returned NULL", size);
  86.     /*NOTREACHED*/
  87.     }
  88.     *(int *)ret = X_MAGIC;
  89.     return ret + sizeof(int);
  90. }
  91.  
  92. char *
  93. xrealloc(region, size)
  94.     char *region;            /* region to be realloc'd */
  95.     unsigned size;            /* realloc size */
  96. {
  97.     register char *ret;            /* region returned by realloc */
  98.  
  99.     if (X_CHECK(region) == FAIL) {
  100.     /* what to do with realloc that is reasonable to avoid a panic? */
  101.     /* copy the region to an entirely new malloc'd area */
  102.     ret = xmalloc(size);
  103.     memcpy(ret, region, size);
  104.     return ret;
  105.     }
  106.  
  107.     ((int *)region)[-1] = 0;        /* clear the magic number */
  108.     ret = realloc(region - sizeof(int), size + sizeof(int));
  109.     if (!ret) {
  110.     panic(EX_SOFTWARE, "realloc(0x%lx, %d) returned NULL",
  111.           (long)region, size);
  112.     /*NOTREACHED*/
  113.     }
  114.     *(int *)ret = X_MAGIC;        /* put a magic number back */
  115.     return ret + sizeof(int);
  116. }
  117.  
  118. void
  119. xfree(region)
  120.     char *region;
  121. {
  122.     if (X_CHECK(region) == FAIL) {
  123.     /* it should be safe to ignore double free's */
  124.     return;
  125.     }
  126.     ((int *)region)[-1] = 0;
  127.     (void)free(region - sizeof(int));
  128. }
  129.  
  130.  
  131. /*
  132.  * bmalloc - allocate memory and associate it with a block
  133.  *
  134.  * input:
  135.  *    size - number of bytes to allocate
  136.  *    block - the block to associate it with, 0 ==> master
  137.  *
  138.  * output:
  139.  *    returns a pointer to the allocated storage
  140.  */
  141. char *
  142. bmalloc(size, block)
  143.     unsigned size;        /* number of bytes to allocate */
  144.     struct block *block;    /* block that data belongs to */
  145. {
  146.     struct bseg *newseg;    /* the new segment for this alloc */
  147.  
  148.     /* a zero block implies master block */
  149.     if (block == 0) {
  150.     block = def_block;
  151.     }
  152.  
  153.     /* add a new segment to the block */
  154.     if ((newseg = (struct bseg *)malloc(sizeof(struct bseg))) == NULL) {
  155.     panic(EX_SOFTWARE, "bmalloc: malloc of bseg failed");
  156.     /* NOTREACHED */
  157.     }
  158.     newseg->next = block->next;
  159.     block->next = newseg; 
  160.  
  161.     /* allocate the storage */
  162.     if ((newseg->data = malloc(size)) == NULL) {
  163.     panic(EX_SOFTWARE, "bmalloc: malloc of %d bytes failed", size);
  164.     /* NOTREACHED */
  165.     }
  166.     ++block->cnt;
  167.  
  168.     /* return the pointer */
  169.     return newseg->data;
  170. }
  171.  
  172. /*
  173.  * brealloc - reallocate stroage associated with a block
  174.  *
  175.  * Resize a storagg from a block, and perform all needed
  176.  * accounting adjustments.
  177.  *
  178.  * input:
  179.  *    data - pointer to data being realloced
  180.  *    size - the new size
  181.  *    block - the block that data belongs
  182.  *
  183.  * output:
  184.  *    returns a pointer to the re-allocated storage
  185.  */
  186. char *
  187. brealloc(data, size, block)
  188.     char *data;            /* data being re-allocated */
  189.     unsigned size;        /* number of bytes to re-allocate */
  190.     struct block *block;    /* block that data belongs to */
  191. {
  192.     struct bseg *oldseg;    /* old segment associated with data */
  193.  
  194.     /* a zero block implies master block */
  195.     if (block == 0) {
  196.     block = def_block;
  197.     }
  198.  
  199.     /* find the segment */
  200.     for (oldseg=block->next;
  201.      oldseg != NULL && oldseg->data != data;
  202.      oldseg=oldseg->next) {
  203.     }
  204.     if (oldseg == NULL) {
  205.     panic(EX_SOFTWARE, 
  206.         "brealloc: seg (at 0x%lx) not in block (at 0x%lx, cnt:%d)",
  207.         (long)oldseg, (long)block, block->cnt);
  208.     /* NOTREACHED */
  209.     }
  210.  
  211.     /* reallocate */
  212.     if ((oldseg->data = realloc(data, size)) == NULL) {
  213.     panic(EX_SOFTWARE, 
  214.         "brealloc: realloc to %d bytes (at 0x%lx) failed",
  215.         size, (long)oldseg->data);
  216.     /* NOTREACHED */
  217.     }
  218.  
  219.     /* return the pointer */
  220.     return oldseg->data;
  221. }
  222.  
  223. /*
  224.  * bfree - free a signle segment from a block
  225.  *
  226.  * Free a storage from a block, and perform all needed accounting adjustments.
  227.  *
  228.  * input:
  229.  *    data - pointer to data being freed
  230.  *    block - the block that data belongs
  231.  */
  232. void
  233. bfree(data, block)
  234.     char *data;            /* data being freed */
  235.     struct block *block;    /* block that data belongs to */
  236. {
  237.     struct bseg *oldseg;    /* old segment associated with data */
  238.     struct bseg *lastseg;    /* the segment before the deleted segment */
  239.  
  240.     /* firewall */
  241.     if (block == NULL) {
  242.     panic(EX_SOFTWARE, "brealloc: block is NULL");
  243.     /* NOTREACHED */
  244.     }
  245.  
  246.     /* delete the segment from the block */
  247.     for (lastseg=NULL, oldseg=block->next; 
  248.      oldseg!=NULL && oldseg->data!=data;
  249.      lastseg=oldseg, oldseg=oldseg->next) {
  250.     }
  251.     if (oldseg == NULL) {
  252.     panic(EX_SOFTWARE, 
  253.         "bfree: data (at 0x%lx) not in block (at 0x%lx, cnt: %d)",
  254.         (long)data, (long)block, block->cnt);
  255.     /* NOTREACHED */
  256.     }
  257.     if (lastseg == NULL) {
  258.     block->next = oldseg->next;
  259.     } else {
  260.     lastseg->next = oldseg->next;
  261.     }
  262.     --block->cnt;
  263.  
  264.     /* free the data and segment */
  265.     (void) free(oldseg->data);
  266.     (void) free((char *)oldseg);
  267. }
  268.  
  269.  
  270. /*
  271.  * malloc_block - form a new storage block
  272.  *
  273.  * Start a new storage block with no storage allociated with it.
  274.  *
  275.  * NOTE: the block structore becomes a segment from the master block
  276.  *
  277.  * input:
  278.  *    none
  279.  *
  280.  * output:
  281.  *    returns a pointer to the new block
  282.  */
  283. struct block *
  284. malloc_block()
  285. {
  286.     struct block *block;    /* the new block */
  287.  
  288.     /* allocate the block */
  289.     block = (struct block *)bmalloc(sizeof(struct block), master);
  290.     block->cnt = 0;
  291.     block->next = NULL;
  292.  
  293.     /* return the new block */
  294.     return block;
  295. }
  296.  
  297. /*
  298.  * realloc_block - move a segment from one block to another
  299.  *
  300.  * input:
  301.  *    data - the data being moved
  302.  *    oldblock - the block where the segment currently resides
  303.  *    newblock - the block that will hold the new segment
  304.  */
  305. void
  306. realloc_block(data, oldblock, newblock)
  307.     char *data;            /* the data to move */
  308.     struct block *oldblock;    /* the old block */
  309.     struct block *newblock;    /* the new block */
  310. {
  311.     struct bseg *oldseg;    /* old segment associated with data */
  312.     struct bseg *lastseg;    /* the segment before the deleted segment */
  313.  
  314.     /* firewall */
  315.     if (oldblock == NULL && newblock == NULL) {
  316.     panic(EX_SOFTWARE, "realloc_block: oldblock or newblock is NULL");
  317.     /* NOTREACHED */
  318.     }
  319.  
  320.     /* delete the segment from the oldblock */
  321.     for (lastseg=NULL, oldseg=oldblock->next; 
  322.      oldseg!=NULL && oldseg->data!=data;
  323.      lastseg=oldseg, oldseg=oldseg->next) {
  324.     }
  325.     if (oldseg == NULL) {
  326.     panic(EX_SOFTWARE, 
  327.         "realloc_block: data (at 0x%lx) not in block (at 0x%lx, cnt: %d)",
  328.         (long)data, (long)oldblock, oldblock->cnt);
  329.     /* NOTREACHED */
  330.     }
  331.     if (lastseg == NULL) {
  332.     oldblock->next = oldseg->next;
  333.     } else {
  334.     lastseg->next = oldseg->next;
  335.     }
  336.     --oldblock->cnt;
  337.  
  338.     /* add the segment to the new block */
  339.     oldseg->next = newblock->next;
  340.     newblock->next = oldseg; 
  341.     ++newblock->cnt;
  342. }
  343.  
  344. /*
  345.  * free_block - free everything in a block
  346.  *
  347.  * input:
  348.  *    block - the block to free all segments on
  349.  */
  350. void
  351. free_block(block)
  352.     struct block *block;    /* the new to free all segments on */
  353. {
  354.     struct bseg *oldseg;    /* the segement to free */
  355.  
  356.     /* firewall */
  357.     if (block == NULL) {
  358.     panic(EX_SOFTWARE, "free_block: block is NULL");
  359.     /* NOTREACHED */
  360.     }
  361.  
  362.     /* free the chain */
  363.     for(oldseg = block->next; 
  364.     block->cnt > 0 && block->next != NULL;
  365.     --block->cnt, block->next = oldseg->next) {
  366.  
  367.     /* free the data */
  368.     (void) free(block->next->data);
  369.     /* free the segemtn */
  370.     (void) free((char *)block->next);
  371.     --block->cnt;
  372.     }
  373.  
  374.     /* firewall */
  375.     if (block->cnt != 0 || block->next != NULL) {
  376.     panic(EX_SOFTWARE, 
  377.       "free_block: freed block (at 0x%lx) has cnt:%d, next:0x%lx",
  378.       (long)block, block->cnt, (long)block->next);
  379.     /* NOTREACHED */
  380.     }
  381. }
  382.